use rand::Rng;
use std::collections::VecDeque;
use std::time::{Duration, Instant};
use std::io;
use crossterm::{
    event::{self, Event, KeyCode},
    execute,
    terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
};
use tui::{
    backend::CrosstermBackend,
    layout::{Constraint, Direction, Layout},
    style::{Color, Style},
    text::Span,
    widgets::{Block, Borders},
    Terminal,
};

struct Game {
    width: u16,
    height: u16,
    snake: VecDeque<(u16, u16)>,
    food: (u16, u16),
    direction: (i16, i16),
    game_over: bool,
}

impl Game {
    fn new(width: u16, height: u16) -> Self {
        let mut snake = VecDeque::new();
        snake.push_back((width / 2 * 2, height / 2));
        
        Self {
            width,
            height,
            snake,
            food: Game::generate_food(width, height),
            direction: (2, 0),
            game_over: false,
        }
    }

    fn generate_food(width: u16, height: u16) -> (u16, u16) {
        let mut rng = rand::thread_rng();
        (rng.gen_range(1..width - 1) * 2, rng.gen_range(1..height - 1))
    }

    fn update(&mut self) {
        if self.game_over {
            return;
        }

        let &(x, y) = self.snake.back().unwrap();
        let new_head = (
            (x as i16 + self.direction.0) as u16,
            (y as i16 + self.direction.1) as u16,
        );

        // Check collision with walls
        if new_head.0 == 0 || new_head.0 >= self.width * 2 ||
           new_head.1 == 0 || new_head.1 >= self.height {
            self.game_over = true;
            return;
        }

        // Check collision with self
        if self.snake.contains(&new_head) {
            self.game_over = true;
            return;
        }

        // Check if eating food
        if new_head == self.food {
            self.food = Game::generate_food(self.width, self.height);
        } else {
            self.snake.pop_front();
        }

        self.snake.push_back(new_head);
    }

    fn change_direction(&mut self, direction: (i16, i16)) {
        if direction.0 != -self.direction.0 || direction.1 != -self.direction.1 {
            self.direction = direction;
        }
    }
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Setup terminal
    enable_raw_mode()?;
    let mut stdout = io::stdout();
    execute!(stdout, EnterAlternateScreen)?;
    let backend = CrosstermBackend::new(stdout);
    let mut terminal = Terminal::new(backend)?;

    // Game setup
    let size = terminal.size()?;
    let (width, height) = ((size.width - 2) / 2, size.height - 2);
    let mut game = Game::new(width, height);
    let tick_rate = Duration::from_millis(100);
    let mut last_tick = Instant::now();

    // Main game loop
    loop {
        terminal.draw(|f| {
            let chunks = Layout::default()
                .direction(Direction::Vertical)
                .constraints([Constraint::Percentage(100)].as_ref())
                .split(f.size());

            let block = Block::default()
                .borders(Borders::ALL)
                .title(Span::styled(
                    "贪吃蛇游戏",
                    Style::default().fg(Color::Green),
                ));
            f.render_widget(block, chunks[0]);

            // Draw snake
            for &(x, y) in &game.snake {
                let x_pos = x;
                let y_pos = y;
                if x_pos < size.width && y_pos < size.height {
                    f.render_widget(
                        Block::default().style(Style::default().bg(Color::Green)),
                        tui::layout::Rect::new(x_pos, y_pos, 2, 1),
                    );
                }
            }

            // Draw food
            f.render_widget(
                Block::default().style(Style::default().bg(Color::Red)),
                tui::layout::Rect::new(game.food.0, game.food.1, 2, 1),
            );

            // Game over message
            if game.game_over {
                let chunks = Layout::default()
                    .constraints(
                        [
                            Constraint::Percentage(33),
                            Constraint::Percentage(33),
                            Constraint::Percentage(33),
                        ]
                        .as_ref(),
                    )
                    .split(f.size());

                let block = Block::default()
                    .borders(Borders::ALL)
                    .title(Span::styled(
                        "游戏结束！按Q退出",
                        Style::default().fg(Color::Red),
                    ));
                f.render_widget(block, chunks[1]);
            }
        })?;

        // Handle input
        let elapsed = last_tick.elapsed();
        if elapsed >= tick_rate {
            game.update();
            last_tick = Instant::now();
        }
        
        if event::poll(tick_rate.saturating_sub(elapsed))? {
            if let Event::Key(key) = event::read()? {
                match key.code {
                    KeyCode::Char('q') => break,
                    KeyCode::Up => game.change_direction((0, -1)),
                    KeyCode::Down => game.change_direction((0, 1)),
                    KeyCode::Left => game.change_direction((-2, 0)),
                    KeyCode::Right => game.change_direction((2, 0)),
                    _ => {}
                }
            }
        }


        if game.game_over {
            break;
        }
    }

    // Cleanup terminal
    disable_raw_mode()?;
    execute!(terminal.backend_mut(), LeaveAlternateScreen)?;
    terminal.show_cursor()?;

    Ok(())
}